// 工具库

// 判断数据是不是对象
export function isObject(data) {
	return typeof data === "object" && data !== null;
}

// 给属性定义不可变属性
export function def(data, key, value) {
	Object.defineProperty(data, key, {
		enumerable: false, // 不能枚举
		configurable: false, // 不可配置,不允许修改
		value,
	});
}

// 创建代理
export function proxy(vm, source, key) {
	// 通过 vm.name 从 vm._data.name 上操作
	Object.defineProperty(vm, key, {
		get() {
			return vm[source][key];
		},
		set(newValue) {
			vm[source][key] = newValue;
		},
	});
}

// 生命周期函数名字
const LIFECYCLE_HOOK = [
	"beforeCreate",
	"create",
	"beforeMount",
	"mounted",
	"beforeUpdate",
	"updated",
	"beforeDestroy",
	"destroyed",
];
// 合并策略
const strategy = {};
// 添加策略
LIFECYCLE_HOOK.forEach((hook) => {
	strategy[hook] = mergeHook;
});

// 合并生命周期
function mergeHook(parent, child) {
	// 新的有
	if (child) {
		// 并且老的也有
		if (parent) {
			// concat 合并数组、合并多个字符串
			return parent.concat(child);
		} else {
			// 老的没有
			return [child];
		}
	} else {
		// 新的没有
		return parent;
	}
}

// 合并自定义组件的策略
strategy.component = function (parent, child) {
	// 先用自身配置的components
	const res = Object.create(parent);
	// 再用全局的
	if (child) {
		for (const key in child) {
			res[key] = child[key];
		}
	}
	return res;
};

// 合并2个对象
export function mergeOptions(parent, child) {
	// 合并好后的对象
	const options = {};
	// 先遍历原来的
	for (const key in parent) {
		// 合并属性
		mergeField(key);
	}
	// 在遍历传来的
	for (const key in child) {
		// 已经处理了的key就不用继续处理了
		if (!parent.hasOwnProperty(key)) {
			// 合并属性
			mergeField(key);
		}
	}
	// 合并属性
	function mergeField(key) {
		// 如果是策略中有的key就按照策略来合并
		if (strategy[key]) {
			// 直接返回新增hook才会变成数组
			return (options[key] = strategy[key](parent[key], child[key]));
		}
		// 如果原来的和传来的都是对象,合并同名对象
		if (isObject(parent[key]) && isObject(child[key])) {
			options[key] = {
				...parent[key],
				...child[key],
			};
		}
		// 如果传来属性的为null或者undefined,就更新原来的属性,合并生命周期需要特殊处理
		else if (!!child[key]) {
			options[key] = child[key];
		} else {
			// 如果传来属性的为null或者undefined,就用原来的属性
			options[key] = parent[key];
		}
	}
	return options;
}

// 存放异步方法的队列
let callbacks = [];
let waiting = false;
// 异步方法
export function nextTick(callback) {
	// 添加到队列
	callbacks.push(callback);
	// 加锁,避免重复执行
	if (!waiting) {
		// 异步执行所有的回调
		setTimeout(() => {
			callbacks.forEach((item) => item());
		}, 0);
		waiting = true;
	}
}

// 格式化时间
function format(time, fmt) {
	var o = {
		"M+": time.getMonth() + 1, //月份
		"d+": time.getDate(), //日
		"h+": time.getHours(), //小时
		"m+": time.getMinutes(), //分
		"s+": time.getSeconds(), //秒
		"q+": Math.floor((time.getMonth() + 3) / 3), //季度
		S: time.getMilliseconds(), //毫秒
	};
	if (/(y+)/.test(fmt)) {
		fmt = fmt.replace(
			RegExp.$1,
			(time.getFullYear() + "").substr(4 - RegExp.$1.length)
		);
	}
	for (var k in o) {
		if (new RegExp("(" + k + ")").test(fmt)) {
			fmt = fmt.replace(
				RegExp.$1,
				RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
			);
		}
	}
	return fmt;
}

// 判断是不是html中的标签
export function isHTMLTag(tagName) {
	const result = {};
	`html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot`
		.split(",")
		.forEach((tag) => {
			result[tag] = true;
		});
	return result[tagName];
}

// 彩色打印,未完成
class Log {
	constructor() {}
	// info
	info(...args) {
		let message = "[INFO]";
		args.forEach((arg) => {
			// 判断是不是对象
			if (isObject(arg)) {
				arg = JSON.stringify(arg);
			}
			message += ` => ${arg}`;
		});
		// 记录执行时间
		const nowTime = Date.now(); // 获取到当前时间
		message += ` => [DATE] => ${format(new Date(), "yyyy-MM-dd hh:mm:ss")}`;
		this.time = nowTime; // 重新初始化执行时间
		console.log(
			`%c ${message}`,
			"color:#27ae60;padding:3px;border-bottom: 1px dashed #95a5a6;"
		);
	}
	// warn
	warn(...args) {
		let message = "[WARN]";
		args.forEach((arg) => {
			// 判断是不是对象
			if (isObject(arg)) {
				arg = JSON.stringify(arg);
			}
			message += ` => ${arg}`;
		});
		// 记录执行时间
		const nowTime = Date.now(); // 获取到当前时间
		message += ` => [DATE] => ${format(new Date(), "yyyy-MM-dd hh:mm:ss")}`;
		this.time = nowTime; // 重新初始化执行时间
		console.log(
			`%c ${message}`,
			"color:#f1c40f;padding:3px;border-bottom: 1px dashed #95a5a6;"
		);
	}
	// error
	error(...args) {
		let message = "[ERROR]";
		args.forEach((arg) => {
			// 判断是不是对象
			if (isObject(arg)) {
				arg = JSON.stringify(arg);
			}
			message += ` => ${arg}`;
		});
		// 记录执行时间
		const nowTime = Date.now(); // 获取到当前时间
		message += ` => [DATE] => ${format(new Date(), "yyyy-MM-dd hh:mm:ss")}`;
		this.time = nowTime; // 重新初始化执行时间
		console.log(
			`%c ${message}`,
			"color:#e74c3c;padding:3px;border-bottom: 1px dashed #95a5a6;"
		);
	}
}

export const logger = new Log();
